library(ggplot2)
library(gridExtra)
library(GGally)
library(corrplot)
library(dplyr)
library(tidyr)
library(viridis)
library(reshape2)

# Configuración general
theme_set(theme_minimal(base_size = 11))

# NOTA: Reemplazar 'ckd_data' con el nombre real de tu dataframe
getwd()  
[1] "/Users/samircabrera/Development/Universidad/Inteligencia Artificial/Inteligencia-Artificial"
setwd("/Users/samircabrera/Development/Universidad/Inteligencia Artificial/Inteligencia-Artificial")  
ckd_data <- read.csv("Chronic_Kidney_Dsease_data.csv")
head(datos)
plot_correlation_matrix <- function(data) {
  # Seleccionar solo variables numéricas relevantes
  numeric_vars <- data %>% 
    select(Age, BMI, SystolicBP, DiastolicBP, FastingBloodSugar, HbA1c,
           SerumCreatinine, BUNLevels, GFR, ProteinInUrine, ACR,
           HemoglobinLevels, CholesterolTotal, CholesterolLDL,
           FatigueLevels, QualityOfLifeScore, MedicationAdherence)
  
  cor_matrix <- cor(numeric_vars, use = "complete.obs")
  
  corrplot(cor_matrix, 
           method = "color",
           type = "upper",
           order = "hclust",  # Agrupación jerárquica
           addrect = 4,       # Marca 4 clusters principales
           tl.col = "black",
           tl.srt = 45,
           tl.cex = 0.8,
           col = colorRampPalette(c("#6D9EC1", "white", "#E46726"))(200),
           title = "Matriz de Correlación con Clustering Jerárquico",
           mar = c(0,0,2,0))
}
plot_renal_pairs <- function(data) {
  renal_data <- data %>%
    select(GFR, SerumCreatinine, BUNLevels, ProteinInUrine, ACR, Diagnosis) %>%
    mutate(Diagnosis = factor(Diagnosis, labels = c("No CKD", "CKD")))
  
  ggpairs(renal_data,
          columns = 1:5,
          aes(color = Diagnosis, alpha = 0.5),
          upper = list(continuous = wrap("cor", size = 3)),
          lower = list(continuous = wrap("points", alpha = 0.3, size = 0.5)),
          diag = list(continuous = wrap("densityDiag", alpha = 0.5)),
          title = "Relaciones entre Marcadores Renales (por Diagnosis)") +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"))
}
plot_gfr_3d <- function(data) {
  data_plot <- data %>%
    mutate(Diagnosis = factor(Diagnosis, labels = c("No CKD", "CKD")))
  
  ggplot(data_plot, aes(x = SerumCreatinine, y = GFR)) +
    geom_point(aes(color = Age, size = BMI, shape = Diagnosis), alpha = 0.6) +
    scale_color_viridis(option = "plasma") +
    scale_size_continuous(range = c(1, 6)) +
    geom_smooth(aes(linetype = Diagnosis), method = "loess", se = TRUE, 
                color = "black", size = 0.8) +
    labs(title = "GFR vs Creatinina (Edad en color, BMI en tamaño)",
         x = "Creatinina Sérica (mg/dL)",
         y = "GFR (mL/min/1.73m²)",
         caption = "Las líneas muestran tendencias por grupo de diagnóstico") +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"),
          legend.position = "right")
}
plot_clinical_heatmap <- function(data) {
  # Crear estadios de CKD basados en GFR
  data_staged <- data %>%
    mutate(CKD_Stage = case_when(
      GFR >= 90 ~ "Normal (≥90)",
      GFR >= 60 ~ "Mild (60-89)",
      GFR >= 30 ~ "Moderate (30-59)",
      GFR >= 15 ~ "Severe (15-29)",
      TRUE ~ "Kidney Failure (<15)"
    )) %>%
    mutate(CKD_Stage = factor(CKD_Stage, 
                              levels = c("Normal (≥90)", "Mild (60-89)", 
                                         "Moderate (30-59)", "Severe (15-29)", 
                                         "Kidney Failure (<15)")))
  
  # Calcular promedios por estadio
  heatmap_data <- data_staged %>%
    group_by(CKD_Stage) %>%
    summarise(
      BMI = mean(BMI, na.rm = TRUE),
      SystolicBP = mean(SystolicBP, na.rm = TRUE),
      HbA1c = mean(HbA1c, na.rm = TRUE),
      Creatinine = mean(SerumCreatinine, na.rm = TRUE),
      Hemoglobin = mean(HemoglobinLevels, na.rm = TRUE),
      ProteinUrine = mean(ProteinInUrine, na.rm = TRUE),
      Fatigue = mean(FatigueLevels, na.rm = TRUE),
      QoL = mean(QualityOfLifeScore, na.rm = TRUE)
    ) %>%
    pivot_longer(-CKD_Stage, names_to = "Variable", values_to = "Value") %>%
    group_by(Variable) %>%
    mutate(Value_scaled = scale(Value)[,1])  # Estandarizar por variable
  
  ggplot(heatmap_data, aes(x = CKD_Stage, y = Variable, fill = Value_scaled)) +
    geom_tile(color = "white", size = 0.5) +
    geom_text(aes(label = round(Value, 1)), size = 3, color = "white") +
    scale_fill_gradient2(low = "#3B9AB2", mid = "#EBCC2A", high = "#F21A00",
                         midpoint = 0, name = "Z-score") +
    labs(title = "Perfil Clínico Promedio por Estadio de CKD",
         x = "Estadio de Enfermedad Renal",
         y = "Variable Clínica",
         caption = "Valores estandarizados (Z-scores) - números = valor real promedio") +
    theme(axis.text.x = element_text(angle = 45, hjust = 1),
          plot.title = element_text(hjust = 0.5, face = "bold"))
}
plot_parallel_coordinates <- function(data) {
  parallel_data <- data %>%
    select(PatientID, BMI, PhysicalActivity, DietQuality, SleepQuality,
           AlcoholConsumption, Smoking, Diagnosis) %>%
    mutate(Diagnosis = factor(Diagnosis, labels = c("No CKD", "CKD"))) %>%
    # Estandarizar variables para escala común
    mutate(across(c(BMI, PhysicalActivity, DietQuality, SleepQuality, 
                    AlcoholConsumption), scale)) %>%
    sample_n(200)  # Muestra para claridad visual
  
  parallel_long <- parallel_data %>%
    pivot_longer(cols = c(BMI, PhysicalActivity, DietQuality, 
                          SleepQuality, AlcoholConsumption),
                 names_to = "Variable", values_to = "Value") %>%
    mutate(Variable = factor(Variable, 
                             levels = c("BMI", "PhysicalActivity", "DietQuality",
                                        "SleepQuality", "AlcoholConsumption")))
  
  ggplot(parallel_long, aes(x = Variable, y = Value, group = PatientID)) +
    geom_line(aes(color = Diagnosis), alpha = 0.3, size = 0.5) +
    geom_point(aes(color = Diagnosis), alpha = 0.4, size = 1) +
    scale_color_manual(values = c("No CKD" = "#00BA38", "CKD" = "#F8766D")) +
    labs(title = "Perfiles de Estilo de Vida (Parallel Coordinates)",
         subtitle = "Muestra de 200 pacientes - Variables estandarizadas",
         y = "Valor Estandarizado (Z-score)",
         x = "") +
    theme(axis.text.x = element_text(angle = 45, hjust = 1),
          plot.title = element_text(hjust = 0.5, face = "bold"),
          plot.subtitle = element_text(hjust = 0.5))
}
plot_demographic_boxplots <- function(data) {
  data_demo <- data %>%
    mutate(
      Gender = factor(Gender, labels = c("Male", "Female")),
      Ethnicity = factor(Ethnicity, labels = c("Caucasian", "African American", 
                                               "Asian", "Other")),
      SocioeconomicStatus = factor(SocioeconomicStatus, 
                                   labels = c("Low", "Middle", "High"))
    ) %>%
    select(Gender, Ethnicity, SocioeconomicStatus, GFR, HbA1c, 
           SystolicBP, QualityOfLifeScore) %>%
    pivot_longer(cols = c(GFR, HbA1c, SystolicBP, QualityOfLifeScore),
                 names_to = "Biomarker", values_to = "Value")
  
  ggplot(data_demo, aes(x = SocioeconomicStatus, y = Value, fill = Gender)) +
    geom_boxplot(alpha = 0.7, outlier.size = 0.5) +
    facet_grid(Biomarker ~ Ethnicity, scales = "free_y") +
    scale_fill_brewer(palette = "Set2") +
    labs(title = "Biomarcadores por Demografía (Género, Etnicidad, Estatus Socioeconómico)",
         x = "Estatus Socioeconómico",
         y = "Valor del Biomarcador") +
    theme(strip.text = element_text(face = "bold", size = 8),
          axis.text.x = element_text(angle = 45, hjust = 1),
          plot.title = element_text(hjust = 0.5, face = "bold", size = 11))
}
plot_qol_bubble <- function(data) {
  bubble_data <- data %>%
    mutate(
      Severity_Score = (SerumCreatinine - min(SerumCreatinine)) / 
        (max(SerumCreatinine) - min(SerumCreatinine)) * 10,
      Diagnosis = factor(Diagnosis, labels = c("No CKD", "CKD"))
    )
  
  ggplot(bubble_data, aes(x = FatigueLevels, y = QualityOfLifeScore)) +
    geom_point(aes(size = Severity_Score, color = GFR, shape = Diagnosis), 
               alpha = 0.6) +
    scale_color_viridis(option = "magma", direction = -1, 
                        name = "GFR\n(mL/min/1.73m²)") +
    scale_size_continuous(range = c(1, 10), 
                          name = "Severidad\n(Creatinina)") +
    geom_smooth(aes(color = NULL, size = NULL), method = "lm", 
                se = TRUE, color = "black", linetype = "dashed") +
    labs(title = "Calidad de Vida vs Fatiga (tamaño = Severidad, color = GFR)",
         x = "Nivel de Fatiga (0-10)",
         y = "Score de Calidad de Vida (0-100)") +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"),
          legend.position = "right")
}
plot_medication_violins <- function(data) {
  med_data <- data %>%
    mutate(
      Treatment_Intensity = ACEInhibitors + Diuretics + Statins + 
        AntidiabeticMedications,
      Treatment_Group = case_when(
        Treatment_Intensity == 0 ~ "No Meds",
        Treatment_Intensity <= 2 ~ "Low (1-2)",
        TRUE ~ "High (3-4)"
      ),
      Treatment_Group = factor(Treatment_Group, 
                               levels = c("No Meds", "Low (1-2)", "High (3-4)"))
    ) %>%
    select(Treatment_Group, GFR, HbA1c, SystolicBP, QualityOfLifeScore) %>%
    pivot_longer(cols = c(GFR, HbA1c, SystolicBP, QualityOfLifeScore),
                 names_to = "Outcome", values_to = "Value")
  
  ggplot(med_data, aes(x = Treatment_Group, y = Value, fill = Treatment_Group)) +
    geom_violin(alpha = 0.7, trim = FALSE) +
    geom_boxplot(width = 0.2, alpha = 0.8, outlier.size = 0.5) +
    facet_wrap(~ Outcome, scales = "free_y", ncol = 2) +
    scale_fill_brewer(palette = "YlOrRd") +
    labs(title = "Distribución de Outcomes Clínicos por Intensidad de Tratamiento",
         subtitle = "Intensidad = suma de medicamentos clave (ACEi, Diurético, Estatina, Antidiabético)",
         x = "Grupo de Tratamiento",
         y = "Valor del Outcome",
         fill = "Intensidad") +
    theme(strip.text = element_text(face = "bold"),
          axis.text.x = element_text(angle = 45, hjust = 1),
          plot.title = element_text(hjust = 0.5, face = "bold"),
          plot.subtitle = element_text(hjust = 0.5, size = 9))
}
plot_density_contour <- function(data) {
  data_contour <- data %>%
    mutate(Diagnosis = factor(Diagnosis, labels = c("No CKD", "CKD")))
  
  ggplot(data_contour, aes(x = HbA1c, y = GFR)) +
    stat_density_2d(aes(fill = after_stat(level)), geom = "polygon", alpha = 0.5) +
    geom_point(aes(color = Diagnosis), alpha = 0.3, size = 1) +
    scale_fill_viridis(option = "cividis", name = "Densidad") +
    scale_color_manual(values = c("No CKD" = "#00BA38", "CKD" = "#F8766D")) +
    geom_hline(yintercept = 60, linetype = "dashed", color = "red", size = 0.8) +
    annotate("text", x = 9, y = 65, label = "GFR = 60 (umbral CKD)", 
             color = "red", size = 3) +
    labs(title = "Contorno de Densidad: GFR vs HbA1c",
         subtitle = "Identificación de clusters de riesgo metabólico-renal",
         x = "HbA1c (%)",
         y = "GFR (mL/min/1.73m²)") +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"),
          plot.subtitle = element_text(hjust = 0.5))
}
plot_age_ridges <- function(data) {
  library(ggridges)
  
  ridge_data <- data %>%
    mutate(
      Comorbidity_Profile = case_when(
        FamilyHistoryDiabetes == 1 & FamilyHistoryHypertension == 1 ~ 
          "Diabetes + HTN",
        FamilyHistoryDiabetes == 1 ~ "Diabetes Only",
        FamilyHistoryHypertension == 1 ~ "HTN Only",
        FamilyHistoryKidneyDisease == 1 ~ "Kidney Disease",
        TRUE ~ "None"
      )
    ) %>%
    filter(Comorbidity_Profile != "None")
  
  ggplot(ridge_data, aes(x = Age, y = Comorbidity_Profile, fill = Comorbidity_Profile)) +
    geom_density_ridges(alpha = 0.7, scale = 1.5) +
    scale_fill_viridis(discrete = TRUE, option = "turbo") +
    labs(title = "Distribución de Edad según Historia Familiar de Comorbilidades",
         x = "Edad (años)",
         y = "Perfil de Comorbilidad Familiar") +
    theme_ridges() +
    theme(legend.position = "none",
          plot.title = element_text(hjust = 0.5, face = "bold"))
}
generate_all_plots <- function(data) {
  # Crear lista para almacenar plots
  plots <- list()
  
  cat("Generando visualizaciones multivariables...\n\n")
  
  cat("1. Matriz de Correlación con Clustering...\n")
  plot_correlation_matrix(data)
  
  cat("2. Pairplot de Variables Renales...\n")
  plots$renal_pairs <- plot_renal_pairs(data)
  print(plots$renal_pairs)
  
  cat("3. Scatterplot 4D (GFR-Creatinina-Edad-BMI)...\n")
  plots$gfr_3d <- plot_gfr_3d(data)
  print(plots$gfr_3d)
  
  cat("4. Heatmap de Perfiles Clínicos...\n")
  plots$heatmap <- plot_clinical_heatmap(data)
  print(plots$heatmap)
  
  cat("5. Parallel Coordinates (Factores de Riesgo)...\n")
  plots$parallel <- plot_parallel_coordinates(data)
  print(plots$parallel)
  
  cat("6. Boxplots Demográficos Facetados...\n")
  plots$demo_box <- plot_demographic_boxplots(data)
  print(plots$demo_box)
  
  cat("7. Bubble Chart (Calidad de Vida)...\n")
  plots$bubble <- plot_qol_bubble(data)
  print(plots$bubble)
  
  cat("8. Violin Plots (Medicamentos)...\n")
  plots$violins <- plot_medication_violins(data)
  print(plots$violins)
  
  cat("9. Contour Plot (Densidad GFR-HbA1c)...\n")
  plots$contour <- plot_density_contour(data)
  print(plots$contour)
  
  cat("10. Ridge Plot (Edad por Comorbilidades)...\n")
  plots$ridges <- plot_age_ridges(data)
  print(plots$ridges)
  
  cat("\n¡Todas las visualizaciones generadas exitosamente!\n")
  
  return(invisible(plots))
}
plots <- generate_all_plots(ckd_data)
Generando visualizaciones multivariables...

1. Matriz de Correlación con Clustering...
2. Pairplot de Variables Renales...
3. Scatterplot 4D (GFR-Creatinina-Edad-BMI)...
4. Heatmap de Perfiles Clínicos...
5. Parallel Coordinates (Factores de Riesgo)...
6. Boxplots Demográficos Facetados...
7. Bubble Chart (Calidad de Vida)...
8. Violin Plots (Medicamentos)...
9. Contour Plot (Densidad GFR-HbA1c)...
10. Ridge Plot (Edad por Comorbilidades)...

¡Todas las visualizaciones generadas exitosamente!

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KEdHYWxseSkKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KHJlc2hhcGUyKQoKIyBDb25maWd1cmFjacOzbiBnZW5lcmFsCnRoZW1lX3NldCh0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDExKSkKCiMgTk9UQTogUmVlbXBsYXphciAnY2tkX2RhdGEnIGNvbiBlbCBub21icmUgcmVhbCBkZSB0dSBkYXRhZnJhbWUKZ2V0d2QoKSAgCnNldHdkKCIvVXNlcnMvc2FtaXJjYWJyZXJhL0RldmVsb3BtZW50L1VuaXZlcnNpZGFkL0ludGVsaWdlbmNpYSBBcnRpZmljaWFsL0ludGVsaWdlbmNpYS1BcnRpZmljaWFsIikgIApja2RfZGF0YSA8LSByZWFkLmNzdigiQ2hyb25pY19LaWRuZXlfRHNlYXNlX2RhdGEuY3N2IikKaGVhZChkYXRvcykKYGBgCmBgYHtyfQpwbG90X2NvcnJlbGF0aW9uX21hdHJpeCA8LSBmdW5jdGlvbihkYXRhKSB7CiAgIyBTZWxlY2Npb25hciBzb2xvIHZhcmlhYmxlcyBudW3DqXJpY2FzIHJlbGV2YW50ZXMKICBudW1lcmljX3ZhcnMgPC0gZGF0YSAlPiUgCiAgICBzZWxlY3QoQWdlLCBCTUksIFN5c3RvbGljQlAsIERpYXN0b2xpY0JQLCBGYXN0aW5nQmxvb2RTdWdhciwgSGJBMWMsCiAgICAgICAgICAgU2VydW1DcmVhdGluaW5lLCBCVU5MZXZlbHMsIEdGUiwgUHJvdGVpbkluVXJpbmUsIEFDUiwKICAgICAgICAgICBIZW1vZ2xvYmluTGV2ZWxzLCBDaG9sZXN0ZXJvbFRvdGFsLCBDaG9sZXN0ZXJvbExETCwKICAgICAgICAgICBGYXRpZ3VlTGV2ZWxzLCBRdWFsaXR5T2ZMaWZlU2NvcmUsIE1lZGljYXRpb25BZGhlcmVuY2UpCiAgCiAgY29yX21hdHJpeCA8LSBjb3IobnVtZXJpY192YXJzLCB1c2UgPSAiY29tcGxldGUub2JzIikKICAKICBjb3JycGxvdChjb3JfbWF0cml4LCAKICAgICAgICAgICBtZXRob2QgPSAiY29sb3IiLAogICAgICAgICAgIHR5cGUgPSAidXBwZXIiLAogICAgICAgICAgIG9yZGVyID0gImhjbHVzdCIsICAjIEFncnVwYWNpw7NuIGplcsOhcnF1aWNhCiAgICAgICAgICAgYWRkcmVjdCA9IDQsICAgICAgICMgTWFyY2EgNCBjbHVzdGVycyBwcmluY2lwYWxlcwogICAgICAgICAgIHRsLmNvbCA9ICJibGFjayIsCiAgICAgICAgICAgdGwuc3J0ID0gNDUsCiAgICAgICAgICAgdGwuY2V4ID0gMC44LAogICAgICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUoYygiIzZEOUVDMSIsICJ3aGl0ZSIsICIjRTQ2NzI2IikpKDIwMCksCiAgICAgICAgICAgdGl0bGUgPSAiTWF0cml6IGRlIENvcnJlbGFjacOzbiBjb24gQ2x1c3RlcmluZyBKZXLDoXJxdWljbyIsCiAgICAgICAgICAgbWFyID0gYygwLDAsMiwwKSkKfQpgYGAKCgpgYGB7cn0KcGxvdF9yZW5hbF9wYWlycyA8LSBmdW5jdGlvbihkYXRhKSB7CiAgcmVuYWxfZGF0YSA8LSBkYXRhICU+JQogICAgc2VsZWN0KEdGUiwgU2VydW1DcmVhdGluaW5lLCBCVU5MZXZlbHMsIFByb3RlaW5JblVyaW5lLCBBQ1IsIERpYWdub3NpcykgJT4lCiAgICBtdXRhdGUoRGlhZ25vc2lzID0gZmFjdG9yKERpYWdub3NpcywgbGFiZWxzID0gYygiTm8gQ0tEIiwgIkNLRCIpKSkKICAKICBnZ3BhaXJzKHJlbmFsX2RhdGEsCiAgICAgICAgICBjb2x1bW5zID0gMTo1LAogICAgICAgICAgYWVzKGNvbG9yID0gRGlhZ25vc2lzLCBhbHBoYSA9IDAuNSksCiAgICAgICAgICB1cHBlciA9IGxpc3QoY29udGludW91cyA9IHdyYXAoImNvciIsIHNpemUgPSAzKSksCiAgICAgICAgICBsb3dlciA9IGxpc3QoY29udGludW91cyA9IHdyYXAoInBvaW50cyIsIGFscGhhID0gMC4zLCBzaXplID0gMC41KSksCiAgICAgICAgICBkaWFnID0gbGlzdChjb250aW51b3VzID0gd3JhcCgiZGVuc2l0eURpYWciLCBhbHBoYSA9IDAuNSkpLAogICAgICAgICAgdGl0bGUgPSAiUmVsYWNpb25lcyBlbnRyZSBNYXJjYWRvcmVzIFJlbmFsZXMgKHBvciBEaWFnbm9zaXMpIikgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpCn0KYGBgCgpgYGB7cn0KcGxvdF9nZnJfM2QgPC0gZnVuY3Rpb24oZGF0YSkgewogIGRhdGFfcGxvdCA8LSBkYXRhICU+JQogICAgbXV0YXRlKERpYWdub3NpcyA9IGZhY3RvcihEaWFnbm9zaXMsIGxhYmVscyA9IGMoIk5vIENLRCIsICJDS0QiKSkpCiAgCiAgZ2dwbG90KGRhdGFfcGxvdCwgYWVzKHggPSBTZXJ1bUNyZWF0aW5pbmUsIHkgPSBHRlIpKSArCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IEFnZSwgc2l6ZSA9IEJNSSwgc2hhcGUgPSBEaWFnbm9zaXMpLCBhbHBoYSA9IDAuNikgKwogICAgc2NhbGVfY29sb3JfdmlyaWRpcyhvcHRpb24gPSAicGxhc21hIikgKwogICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygxLCA2KSkgKwogICAgZ2VvbV9zbW9vdGgoYWVzKGxpbmV0eXBlID0gRGlhZ25vc2lzKSwgbWV0aG9kID0gImxvZXNzIiwgc2UgPSBUUlVFLCAKICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuOCkgKwogICAgbGFicyh0aXRsZSA9ICJHRlIgdnMgQ3JlYXRpbmluYSAoRWRhZCBlbiBjb2xvciwgQk1JIGVuIHRhbWHDsW8pIiwKICAgICAgICAgeCA9ICJDcmVhdGluaW5hIFPDqXJpY2EgKG1nL2RMKSIsCiAgICAgICAgIHkgPSAiR0ZSIChtTC9taW4vMS43M23CsikiLAogICAgICAgICBjYXB0aW9uID0gIkxhcyBsw61uZWFzIG11ZXN0cmFuIHRlbmRlbmNpYXMgcG9yIGdydXBvIGRlIGRpYWduw7NzdGljbyIpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKfQpgYGAKCmBgYHtyfQpwbG90X2NsaW5pY2FsX2hlYXRtYXAgPC0gZnVuY3Rpb24oZGF0YSkgewogICMgQ3JlYXIgZXN0YWRpb3MgZGUgQ0tEIGJhc2Fkb3MgZW4gR0ZSCiAgZGF0YV9zdGFnZWQgPC0gZGF0YSAlPiUKICAgIG11dGF0ZShDS0RfU3RhZ2UgPSBjYXNlX3doZW4oCiAgICAgIEdGUiA+PSA5MCB+ICJOb3JtYWwgKOKJpTkwKSIsCiAgICAgIEdGUiA+PSA2MCB+ICJNaWxkICg2MC04OSkiLAogICAgICBHRlIgPj0gMzAgfiAiTW9kZXJhdGUgKDMwLTU5KSIsCiAgICAgIEdGUiA+PSAxNSB+ICJTZXZlcmUgKDE1LTI5KSIsCiAgICAgIFRSVUUgfiAiS2lkbmV5IEZhaWx1cmUgKDwxNSkiCiAgICApKSAlPiUKICAgIG11dGF0ZShDS0RfU3RhZ2UgPSBmYWN0b3IoQ0tEX1N0YWdlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiTm9ybWFsICjiiaU5MCkiLCAiTWlsZCAoNjAtODkpIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1vZGVyYXRlICgzMC01OSkiLCAiU2V2ZXJlICgxNS0yOSkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS2lkbmV5IEZhaWx1cmUgKDwxNSkiKSkpCiAgCiAgIyBDYWxjdWxhciBwcm9tZWRpb3MgcG9yIGVzdGFkaW8KICBoZWF0bWFwX2RhdGEgPC0gZGF0YV9zdGFnZWQgJT4lCiAgICBncm91cF9ieShDS0RfU3RhZ2UpICU+JQogICAgc3VtbWFyaXNlKAogICAgICBCTUkgPSBtZWFuKEJNSSwgbmEucm0gPSBUUlVFKSwKICAgICAgU3lzdG9saWNCUCA9IG1lYW4oU3lzdG9saWNCUCwgbmEucm0gPSBUUlVFKSwKICAgICAgSGJBMWMgPSBtZWFuKEhiQTFjLCBuYS5ybSA9IFRSVUUpLAogICAgICBDcmVhdGluaW5lID0gbWVhbihTZXJ1bUNyZWF0aW5pbmUsIG5hLnJtID0gVFJVRSksCiAgICAgIEhlbW9nbG9iaW4gPSBtZWFuKEhlbW9nbG9iaW5MZXZlbHMsIG5hLnJtID0gVFJVRSksCiAgICAgIFByb3RlaW5VcmluZSA9IG1lYW4oUHJvdGVpbkluVXJpbmUsIG5hLnJtID0gVFJVRSksCiAgICAgIEZhdGlndWUgPSBtZWFuKEZhdGlndWVMZXZlbHMsIG5hLnJtID0gVFJVRSksCiAgICAgIFFvTCA9IG1lYW4oUXVhbGl0eU9mTGlmZVNjb3JlLCBuYS5ybSA9IFRSVUUpCiAgICApICU+JQogICAgcGl2b3RfbG9uZ2VyKC1DS0RfU3RhZ2UsIG5hbWVzX3RvID0gIlZhcmlhYmxlIiwgdmFsdWVzX3RvID0gIlZhbHVlIikgJT4lCiAgICBncm91cF9ieShWYXJpYWJsZSkgJT4lCiAgICBtdXRhdGUoVmFsdWVfc2NhbGVkID0gc2NhbGUoVmFsdWUpWywxXSkgICMgRXN0YW5kYXJpemFyIHBvciB2YXJpYWJsZQogIAogIGdncGxvdChoZWF0bWFwX2RhdGEsIGFlcyh4ID0gQ0tEX1N0YWdlLCB5ID0gVmFyaWFibGUsIGZpbGwgPSBWYWx1ZV9zY2FsZWQpKSArCiAgICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiLCBzaXplID0gMC41KSArCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoVmFsdWUsIDEpKSwgc2l6ZSA9IDMsIGNvbG9yID0gIndoaXRlIikgKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gIiMzQjlBQjIiLCBtaWQgPSAiI0VCQ0MyQSIsIGhpZ2ggPSAiI0YyMUEwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAsIG5hbWUgPSAiWi1zY29yZSIpICsKICAgIGxhYnModGl0bGUgPSAiUGVyZmlsIENsw61uaWNvIFByb21lZGlvIHBvciBFc3RhZGlvIGRlIENLRCIsCiAgICAgICAgIHggPSAiRXN0YWRpbyBkZSBFbmZlcm1lZGFkIFJlbmFsIiwKICAgICAgICAgeSA9ICJWYXJpYWJsZSBDbMOtbmljYSIsCiAgICAgICAgIGNhcHRpb24gPSAiVmFsb3JlcyBlc3RhbmRhcml6YWRvcyAoWi1zY29yZXMpIC0gbsO6bWVyb3MgPSB2YWxvciByZWFsIHByb21lZGlvIikgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQp9CmBgYAoKYGBge3J9CnBsb3RfcGFyYWxsZWxfY29vcmRpbmF0ZXMgPC0gZnVuY3Rpb24oZGF0YSkgewogIHBhcmFsbGVsX2RhdGEgPC0gZGF0YSAlPiUKICAgIHNlbGVjdChQYXRpZW50SUQsIEJNSSwgUGh5c2ljYWxBY3Rpdml0eSwgRGlldFF1YWxpdHksIFNsZWVwUXVhbGl0eSwKICAgICAgICAgICBBbGNvaG9sQ29uc3VtcHRpb24sIFNtb2tpbmcsIERpYWdub3NpcykgJT4lCiAgICBtdXRhdGUoRGlhZ25vc2lzID0gZmFjdG9yKERpYWdub3NpcywgbGFiZWxzID0gYygiTm8gQ0tEIiwgIkNLRCIpKSkgJT4lCiAgICAjIEVzdGFuZGFyaXphciB2YXJpYWJsZXMgcGFyYSBlc2NhbGEgY29tw7puCiAgICBtdXRhdGUoYWNyb3NzKGMoQk1JLCBQaHlzaWNhbEFjdGl2aXR5LCBEaWV0UXVhbGl0eSwgU2xlZXBRdWFsaXR5LCAKICAgICAgICAgICAgICAgICAgICBBbGNvaG9sQ29uc3VtcHRpb24pLCBzY2FsZSkpICU+JQogICAgc2FtcGxlX24oMjAwKSAgIyBNdWVzdHJhIHBhcmEgY2xhcmlkYWQgdmlzdWFsCiAgCiAgcGFyYWxsZWxfbG9uZyA8LSBwYXJhbGxlbF9kYXRhICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKEJNSSwgUGh5c2ljYWxBY3Rpdml0eSwgRGlldFF1YWxpdHksIAogICAgICAgICAgICAgICAgICAgICAgICAgIFNsZWVwUXVhbGl0eSwgQWxjb2hvbENvbnN1bXB0aW9uKSwKICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJWYXJpYWJsZSIsIHZhbHVlc190byA9ICJWYWx1ZSIpICU+JQogICAgbXV0YXRlKFZhcmlhYmxlID0gZmFjdG9yKFZhcmlhYmxlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJCTUkiLCAiUGh5c2ljYWxBY3Rpdml0eSIsICJEaWV0UXVhbGl0eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2xlZXBRdWFsaXR5IiwgIkFsY29ob2xDb25zdW1wdGlvbiIpKSkKICAKICBnZ3Bsb3QocGFyYWxsZWxfbG9uZywgYWVzKHggPSBWYXJpYWJsZSwgeSA9IFZhbHVlLCBncm91cCA9IFBhdGllbnRJRCkpICsKICAgIGdlb21fbGluZShhZXMoY29sb3IgPSBEaWFnbm9zaXMpLCBhbHBoYSA9IDAuMywgc2l6ZSA9IDAuNSkgKwogICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBEaWFnbm9zaXMpLCBhbHBoYSA9IDAuNCwgc2l6ZSA9IDEpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJObyBDS0QiID0gIiMwMEJBMzgiLCAiQ0tEIiA9ICIjRjg3NjZEIikpICsKICAgIGxhYnModGl0bGUgPSAiUGVyZmlsZXMgZGUgRXN0aWxvIGRlIFZpZGEgKFBhcmFsbGVsIENvb3JkaW5hdGVzKSIsCiAgICAgICAgIHN1YnRpdGxlID0gIk11ZXN0cmEgZGUgMjAwIHBhY2llbnRlcyAtIFZhcmlhYmxlcyBlc3RhbmRhcml6YWRhcyIsCiAgICAgICAgIHkgPSAiVmFsb3IgRXN0YW5kYXJpemFkbyAoWi1zY29yZSkiLAogICAgICAgICB4ID0gIiIpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwKICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQp9CmBgYAoKYGBge3J9CnBsb3RfZGVtb2dyYXBoaWNfYm94cGxvdHMgPC0gZnVuY3Rpb24oZGF0YSkgewogIGRhdGFfZGVtbyA8LSBkYXRhICU+JQogICAgbXV0YXRlKAogICAgICBHZW5kZXIgPSBmYWN0b3IoR2VuZGVyLCBsYWJlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpKSwKICAgICAgRXRobmljaXR5ID0gZmFjdG9yKEV0aG5pY2l0eSwgbGFiZWxzID0gYygiQ2F1Y2FzaWFuIiwgIkFmcmljYW4gQW1lcmljYW4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNpYW4iLCAiT3RoZXIiKSksCiAgICAgIFNvY2lvZWNvbm9taWNTdGF0dXMgPSBmYWN0b3IoU29jaW9lY29ub21pY1N0YXR1cywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiTG93IiwgIk1pZGRsZSIsICJIaWdoIikpCiAgICApICU+JQogICAgc2VsZWN0KEdlbmRlciwgRXRobmljaXR5LCBTb2Npb2Vjb25vbWljU3RhdHVzLCBHRlIsIEhiQTFjLCAKICAgICAgICAgICBTeXN0b2xpY0JQLCBRdWFsaXR5T2ZMaWZlU2NvcmUpICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKEdGUiwgSGJBMWMsIFN5c3RvbGljQlAsIFF1YWxpdHlPZkxpZmVTY29yZSksCiAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiQmlvbWFya2VyIiwgdmFsdWVzX3RvID0gIlZhbHVlIikKICAKICBnZ3Bsb3QoZGF0YV9kZW1vLCBhZXMoeCA9IFNvY2lvZWNvbm9taWNTdGF0dXMsIHkgPSBWYWx1ZSwgZmlsbCA9IEdlbmRlcikpICsKICAgIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNywgb3V0bGllci5zaXplID0gMC41KSArCiAgICBmYWNldF9ncmlkKEJpb21hcmtlciB+IEV0aG5pY2l0eSwgc2NhbGVzID0gImZyZWVfeSIpICsKICAgIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsKICAgIGxhYnModGl0bGUgPSAiQmlvbWFyY2Fkb3JlcyBwb3IgRGVtb2dyYWbDrWEgKEfDqW5lcm8sIEV0bmljaWRhZCwgRXN0YXR1cyBTb2Npb2Vjb27Ds21pY28pIiwKICAgICAgICAgeCA9ICJFc3RhdHVzIFNvY2lvZWNvbsOzbWljbyIsCiAgICAgICAgIHkgPSAiVmFsb3IgZGVsIEJpb21hcmNhZG9yIikgKwogICAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gOCksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDExKSkKfQpgYGAKCmBgYHtyfQpwbG90X3FvbF9idWJibGUgPC0gZnVuY3Rpb24oZGF0YSkgewogIGJ1YmJsZV9kYXRhIDwtIGRhdGEgJT4lCiAgICBtdXRhdGUoCiAgICAgIFNldmVyaXR5X1Njb3JlID0gKFNlcnVtQ3JlYXRpbmluZSAtIG1pbihTZXJ1bUNyZWF0aW5pbmUpKSAvIAogICAgICAgIChtYXgoU2VydW1DcmVhdGluaW5lKSAtIG1pbihTZXJ1bUNyZWF0aW5pbmUpKSAqIDEwLAogICAgICBEaWFnbm9zaXMgPSBmYWN0b3IoRGlhZ25vc2lzLCBsYWJlbHMgPSBjKCJObyBDS0QiLCAiQ0tEIikpCiAgICApCiAgCiAgZ2dwbG90KGJ1YmJsZV9kYXRhLCBhZXMoeCA9IEZhdGlndWVMZXZlbHMsIHkgPSBRdWFsaXR5T2ZMaWZlU2NvcmUpKSArCiAgICBnZW9tX3BvaW50KGFlcyhzaXplID0gU2V2ZXJpdHlfU2NvcmUsIGNvbG9yID0gR0ZSLCBzaGFwZSA9IERpYWdub3NpcyksIAogICAgICAgICAgICAgICBhbHBoYSA9IDAuNikgKwogICAgc2NhbGVfY29sb3JfdmlyaWRpcyhvcHRpb24gPSAibWFnbWEiLCBkaXJlY3Rpb24gPSAtMSwgCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiR0ZSXG4obUwvbWluLzEuNzNtwrIpIikgKwogICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygxLCAxMCksIAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiU2V2ZXJpZGFkXG4oQ3JlYXRpbmluYSkiKSArCiAgICBnZW9tX3Ntb290aChhZXMoY29sb3IgPSBOVUxMLCBzaXplID0gTlVMTCksIG1ldGhvZCA9ICJsbSIsIAogICAgICAgICAgICAgICAgc2UgPSBUUlVFLCBjb2xvciA9ICJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgIGxhYnModGl0bGUgPSAiQ2FsaWRhZCBkZSBWaWRhIHZzIEZhdGlnYSAodGFtYcOxbyA9IFNldmVyaWRhZCwgY29sb3IgPSBHRlIpIiwKICAgICAgICAgeCA9ICJOaXZlbCBkZSBGYXRpZ2EgKDAtMTApIiwKICAgICAgICAgeSA9ICJTY29yZSBkZSBDYWxpZGFkIGRlIFZpZGEgKDAtMTAwKSIpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKfQpgYGAKCmBgYHtyfQpwbG90X21lZGljYXRpb25fdmlvbGlucyA8LSBmdW5jdGlvbihkYXRhKSB7CiAgbWVkX2RhdGEgPC0gZGF0YSAlPiUKICAgIG11dGF0ZSgKICAgICAgVHJlYXRtZW50X0ludGVuc2l0eSA9IEFDRUluaGliaXRvcnMgKyBEaXVyZXRpY3MgKyBTdGF0aW5zICsgCiAgICAgICAgQW50aWRpYWJldGljTWVkaWNhdGlvbnMsCiAgICAgIFRyZWF0bWVudF9Hcm91cCA9IGNhc2Vfd2hlbigKICAgICAgICBUcmVhdG1lbnRfSW50ZW5zaXR5ID09IDAgfiAiTm8gTWVkcyIsCiAgICAgICAgVHJlYXRtZW50X0ludGVuc2l0eSA8PSAyIH4gIkxvdyAoMS0yKSIsCiAgICAgICAgVFJVRSB+ICJIaWdoICgzLTQpIgogICAgICApLAogICAgICBUcmVhdG1lbnRfR3JvdXAgPSBmYWN0b3IoVHJlYXRtZW50X0dyb3VwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIk5vIE1lZHMiLCAiTG93ICgxLTIpIiwgIkhpZ2ggKDMtNCkiKSkKICAgICkgJT4lCiAgICBzZWxlY3QoVHJlYXRtZW50X0dyb3VwLCBHRlIsIEhiQTFjLCBTeXN0b2xpY0JQLCBRdWFsaXR5T2ZMaWZlU2NvcmUpICU+JQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKEdGUiwgSGJBMWMsIFN5c3RvbGljQlAsIFF1YWxpdHlPZkxpZmVTY29yZSksCiAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiT3V0Y29tZSIsIHZhbHVlc190byA9ICJWYWx1ZSIpCiAgCiAgZ2dwbG90KG1lZF9kYXRhLCBhZXMoeCA9IFRyZWF0bWVudF9Hcm91cCwgeSA9IFZhbHVlLCBmaWxsID0gVHJlYXRtZW50X0dyb3VwKSkgKwogICAgZ2VvbV92aW9saW4oYWxwaGEgPSAwLjcsIHRyaW0gPSBGQUxTRSkgKwogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4yLCBhbHBoYSA9IDAuOCwgb3V0bGllci5zaXplID0gMC41KSArCiAgICBmYWNldF93cmFwKH4gT3V0Y29tZSwgc2NhbGVzID0gImZyZWVfeSIsIG5jb2wgPSAyKSArCiAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIllsT3JSZCIpICsKICAgIGxhYnModGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZSBPdXRjb21lcyBDbMOtbmljb3MgcG9yIEludGVuc2lkYWQgZGUgVHJhdGFtaWVudG8iLAogICAgICAgICBzdWJ0aXRsZSA9ICJJbnRlbnNpZGFkID0gc3VtYSBkZSBtZWRpY2FtZW50b3MgY2xhdmUgKEFDRWksIERpdXLDqXRpY28sIEVzdGF0aW5hLCBBbnRpZGlhYsOpdGljbykiLAogICAgICAgICB4ID0gIkdydXBvIGRlIFRyYXRhbWllbnRvIiwKICAgICAgICAgeSA9ICJWYWxvciBkZWwgT3V0Y29tZSIsCiAgICAgICAgIGZpbGwgPSAiSW50ZW5zaWRhZCIpICsKICAgIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gOSkpCn0KYGBgCgpgYGB7cn0KcGxvdF9kZW5zaXR5X2NvbnRvdXIgPC0gZnVuY3Rpb24oZGF0YSkgewogIGRhdGFfY29udG91ciA8LSBkYXRhICU+JQogICAgbXV0YXRlKERpYWdub3NpcyA9IGZhY3RvcihEaWFnbm9zaXMsIGxhYmVscyA9IGMoIk5vIENLRCIsICJDS0QiKSkpCiAgCiAgZ2dwbG90KGRhdGFfY29udG91ciwgYWVzKHggPSBIYkExYywgeSA9IEdGUikpICsKICAgIHN0YXRfZGVuc2l0eV8yZChhZXMoZmlsbCA9IGFmdGVyX3N0YXQobGV2ZWwpKSwgZ2VvbSA9ICJwb2x5Z29uIiwgYWxwaGEgPSAwLjUpICsKICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gRGlhZ25vc2lzKSwgYWxwaGEgPSAwLjMsIHNpemUgPSAxKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXMob3B0aW9uID0gImNpdmlkaXMiLCBuYW1lID0gIkRlbnNpZGFkIikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk5vIENLRCIgPSAiIzAwQkEzOCIsICJDS0QiID0gIiNGODc2NkQiKSkgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNjAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjgpICsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDksIHkgPSA2NSwgbGFiZWwgPSAiR0ZSID0gNjAgKHVtYnJhbCBDS0QpIiwgCiAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLCBzaXplID0gMykgKwogICAgbGFicyh0aXRsZSA9ICJDb250b3JubyBkZSBEZW5zaWRhZDogR0ZSIHZzIEhiQTFjIiwKICAgICAgICAgc3VidGl0bGUgPSAiSWRlbnRpZmljYWNpw7NuIGRlIGNsdXN0ZXJzIGRlIHJpZXNnbyBtZXRhYsOzbGljby1yZW5hbCIsCiAgICAgICAgIHggPSAiSGJBMWMgKCUpIiwKICAgICAgICAgeSA9ICJHRlIgKG1ML21pbi8xLjczbcKyKSIpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCn0KYGBgCgpgYGB7cn0KcGxvdF9hZ2VfcmlkZ2VzIDwtIGZ1bmN0aW9uKGRhdGEpIHsKICBsaWJyYXJ5KGdncmlkZ2VzKQogIAogIHJpZGdlX2RhdGEgPC0gZGF0YSAlPiUKICAgIG11dGF0ZSgKICAgICAgQ29tb3JiaWRpdHlfUHJvZmlsZSA9IGNhc2Vfd2hlbigKICAgICAgICBGYW1pbHlIaXN0b3J5RGlhYmV0ZXMgPT0gMSAmIEZhbWlseUhpc3RvcnlIeXBlcnRlbnNpb24gPT0gMSB+IAogICAgICAgICAgIkRpYWJldGVzICsgSFROIiwKICAgICAgICBGYW1pbHlIaXN0b3J5RGlhYmV0ZXMgPT0gMSB+ICJEaWFiZXRlcyBPbmx5IiwKICAgICAgICBGYW1pbHlIaXN0b3J5SHlwZXJ0ZW5zaW9uID09IDEgfiAiSFROIE9ubHkiLAogICAgICAgIEZhbWlseUhpc3RvcnlLaWRuZXlEaXNlYXNlID09IDEgfiAiS2lkbmV5IERpc2Vhc2UiLAogICAgICAgIFRSVUUgfiAiTm9uZSIKICAgICAgKQogICAgKSAlPiUKICAgIGZpbHRlcihDb21vcmJpZGl0eV9Qcm9maWxlICE9ICJOb25lIikKICAKICBnZ3Bsb3QocmlkZ2VfZGF0YSwgYWVzKHggPSBBZ2UsIHkgPSBDb21vcmJpZGl0eV9Qcm9maWxlLCBmaWxsID0gQ29tb3JiaWRpdHlfUHJvZmlsZSkpICsKICAgIGdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGEgPSAwLjcsIHNjYWxlID0gMS41KSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFLCBvcHRpb24gPSAidHVyYm8iKSArCiAgICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgRWRhZCBzZWfDum4gSGlzdG9yaWEgRmFtaWxpYXIgZGUgQ29tb3JiaWxpZGFkZXMiLAogICAgICAgICB4ID0gIkVkYWQgKGHDsW9zKSIsCiAgICAgICAgIHkgPSAiUGVyZmlsIGRlIENvbW9yYmlsaWRhZCBGYW1pbGlhciIpICsKICAgIHRoZW1lX3JpZGdlcygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQp9CmBgYAoKYGBge3J9CmdlbmVyYXRlX2FsbF9wbG90cyA8LSBmdW5jdGlvbihkYXRhKSB7CiAgIyBDcmVhciBsaXN0YSBwYXJhIGFsbWFjZW5hciBwbG90cwogIHBsb3RzIDwtIGxpc3QoKQogIAogIGNhdCgiR2VuZXJhbmRvIHZpc3VhbGl6YWNpb25lcyBtdWx0aXZhcmlhYmxlcy4uLlxuXG4iKQogIAogIGNhdCgiMS4gTWF0cml6IGRlIENvcnJlbGFjacOzbiBjb24gQ2x1c3RlcmluZy4uLlxuIikKICBwbG90X2NvcnJlbGF0aW9uX21hdHJpeChkYXRhKQogIAogIGNhdCgiMi4gUGFpcnBsb3QgZGUgVmFyaWFibGVzIFJlbmFsZXMuLi5cbiIpCiAgcGxvdHMkcmVuYWxfcGFpcnMgPC0gcGxvdF9yZW5hbF9wYWlycyhkYXRhKQogIHByaW50KHBsb3RzJHJlbmFsX3BhaXJzKQogIAogIGNhdCgiMy4gU2NhdHRlcnBsb3QgNEQgKEdGUi1DcmVhdGluaW5hLUVkYWQtQk1JKS4uLlxuIikKICBwbG90cyRnZnJfM2QgPC0gcGxvdF9nZnJfM2QoZGF0YSkKICBwcmludChwbG90cyRnZnJfM2QpCiAgCiAgY2F0KCI0LiBIZWF0bWFwIGRlIFBlcmZpbGVzIENsw61uaWNvcy4uLlxuIikKICBwbG90cyRoZWF0bWFwIDwtIHBsb3RfY2xpbmljYWxfaGVhdG1hcChkYXRhKQogIHByaW50KHBsb3RzJGhlYXRtYXApCiAgCiAgY2F0KCI1LiBQYXJhbGxlbCBDb29yZGluYXRlcyAoRmFjdG9yZXMgZGUgUmllc2dvKS4uLlxuIikKICBwbG90cyRwYXJhbGxlbCA8LSBwbG90X3BhcmFsbGVsX2Nvb3JkaW5hdGVzKGRhdGEpCiAgcHJpbnQocGxvdHMkcGFyYWxsZWwpCiAgCiAgY2F0KCI2LiBCb3hwbG90cyBEZW1vZ3LDoWZpY29zIEZhY2V0YWRvcy4uLlxuIikKICBwbG90cyRkZW1vX2JveCA8LSBwbG90X2RlbW9ncmFwaGljX2JveHBsb3RzKGRhdGEpCiAgcHJpbnQocGxvdHMkZGVtb19ib3gpCiAgCiAgY2F0KCI3LiBCdWJibGUgQ2hhcnQgKENhbGlkYWQgZGUgVmlkYSkuLi5cbiIpCiAgcGxvdHMkYnViYmxlIDwtIHBsb3RfcW9sX2J1YmJsZShkYXRhKQogIHByaW50KHBsb3RzJGJ1YmJsZSkKICAKICBjYXQoIjguIFZpb2xpbiBQbG90cyAoTWVkaWNhbWVudG9zKS4uLlxuIikKICBwbG90cyR2aW9saW5zIDwtIHBsb3RfbWVkaWNhdGlvbl92aW9saW5zKGRhdGEpCiAgcHJpbnQocGxvdHMkdmlvbGlucykKICAKICBjYXQoIjkuIENvbnRvdXIgUGxvdCAoRGVuc2lkYWQgR0ZSLUhiQTFjKS4uLlxuIikKICBwbG90cyRjb250b3VyIDwtIHBsb3RfZGVuc2l0eV9jb250b3VyKGRhdGEpCiAgcHJpbnQocGxvdHMkY29udG91cikKICAKICBjYXQoIjEwLiBSaWRnZSBQbG90IChFZGFkIHBvciBDb21vcmJpbGlkYWRlcykuLi5cbiIpCiAgcGxvdHMkcmlkZ2VzIDwtIHBsb3RfYWdlX3JpZGdlcyhkYXRhKQogIHByaW50KHBsb3RzJHJpZGdlcykKICAKICBjYXQoIlxuwqFUb2RhcyBsYXMgdmlzdWFsaXphY2lvbmVzIGdlbmVyYWRhcyBleGl0b3NhbWVudGUhXG4iKQogIAogIHJldHVybihpbnZpc2libGUocGxvdHMpKQp9CgpgYGAKCmBgYHtyfQpwbG90cyA8LSBnZW5lcmF0ZV9hbGxfcGxvdHMoY2tkX2RhdGEpCmBgYAoKCgo=